/*
 * CPsGroupFile.cpp
 *
 *  Created on: 2018年7月8日
 *      Author: zhengboyuan
 */

#include "CPsGroupFile.h"
#include "TStringUtil.h"
#include "CPsFile.h"


CPsGroupFile::CPsGroupFile()
{
}

CPsGroupFile::~CPsGroupFile()
{
    close();
}

bool CPsGroupFile::open(const char* filepath)
{
    StringArray pathList;
    comn::StringUtil::split(filepath, ',', pathList);
    return openEx(pathList);
}


void CPsGroupFile::close()
{
    closeAllEntry();
}

bool CPsGroupFile::isOpen()
{
    return m_entryArray.size() > 0;
}

int64_t CPsGroupFile::getTotalSize()
{
    int64_t bytes = 0;
    for (size_t i = 0; i < m_entryArray.size(); i ++)
    {
        bytes += m_entryArray[i].file->getTotalSize();
    }
    return bytes;
}

bool CPsGroupFile::getTotalPositionRange(PsFilePosition& beginPos, PsFilePosition& endPos)
{
    if (!isOpen())
    {
        return false;
    }

    PsFilePtr frontFile = m_entryArray.front().file;
    PsFilePtr backFile = m_entryArray.back().file;

    beginPos = frontFile->getBeginPos();
    endPos = backFile->getEndPos();

    return true;
}


PsFilePosition CPsGroupFile::getBeginPos()
{
    PsFilePosition pos = PsFilePosition();
    if (!isOpen())
    {
        return pos;
    }

    PsFilePtr frontFile = m_entryArray.front().file;
    pos = frontFile->getBeginPos();

    return pos;
}

PsFilePosition CPsGroupFile::getEndPos()
{
    PsFilePosition pos = PsFilePosition();
    if (!isOpen())
    {
        return pos;
    }

    PsFilePtr backFile = m_entryArray.back().file;

    pos = backFile->getEndPos();

    return pos;
}

PsFilePosition CPsGroupFile::getBeginKeyPos()
{
    PsFilePosition pos = PsFilePosition();
    if (m_entryArray.size() > 0)
    {
        pos = m_entryArray.front().file->getBeginKeyPos();
    }
    return pos;
}

bool CPsGroupFile::getTotalKeyFrameRange(PsFilePosition& beginPos, PsFilePosition& endPos)
{
    if (!isOpen())
    {
        return false;
    }

    PsFilePtr frontFile = m_entryArray.front().file;
    PsFilePtr backFile = m_entryArray.back().file;

    PsFilePosition tmp;
    bool found = frontFile->getTotalKeyFrameRange(beginPos, tmp);
    backFile->getTotalKeyFrameRange(tmp, endPos);

    return found;
}

bool CPsGroupFile::seek(time_t t, PsFileSeekMode seekMode, PsFilePosition& pos)
{
    size_t index = findEntry(0, t, seekMode);
    if (index == -1)
    {
        return false;
    }

    return m_entryArray[index].file->seek(t, seekMode, pos);
}

bool CPsGroupFile::seekRange(time_t t, uint32_t duration, PsFileSeekMode seekMode, PsFilePosition& beginPos, PsFilePosition& endPos)
{
    size_t beginIndex = findEntry(0, t, seekMode);
    if (beginIndex == -1)
    {
        return false;
    }

    if (!m_entryArray[beginIndex].file->seekRange(t, duration, seekMode, beginPos, endPos))
    {
        return false;
    }

    if (endPos.size == 0)
    {
        size_t endIndex = findEntry(beginIndex, t + duration, seekMode);
        if (endIndex != -1)
        {
            m_entryArray[endIndex].file->seek(t + duration, seekMode, endPos);
        }
        else
        {
            endPos = PsFilePosition();
            endPos.index = m_entryArray.size();
        }
    }
    return true;
}

bool CPsGroupFile::read(const PsFilePosition& pos, PsMPacket& pkt)
{
    if (pos.index < 0 && pos.index >= (int)m_entryArray.size())
    {
        return false;
    }

    return m_entryArray[pos.index].file->read(pos, pkt);
}

bool CPsGroupFile::readRange(const PsFilePosition& beginPos, const PsFilePosition& endPos, PsPacketProc proc, void* userdata)
{
    int beginIndex = beginPos.index;
    if (beginIndex < 0 && beginIndex >= (int)m_entryArray.size())
    {
        return false;
    }

    int endIndex = endPos.index;
    if (endPos.size <= 0)
    {
        endIndex = m_entryArray.size();
    }

    if (beginIndex == endIndex)
    {
        if (!m_entryArray[beginIndex].file->readRange(beginPos, endPos, proc, userdata))
        {
            return false;
        }
		return true;
    }
	else
	{
		PsFilePtr file = m_entryArray[beginIndex].file;
		PsFilePosition subEndPos;
		if (!file->readRange(beginPos, subEndPos, proc, userdata))
		{
			return false;
		}
	}

    for (int i = beginIndex + 1; i < endIndex; i ++)
    {
        PsFilePtr file = m_entryArray[i].file;

        PsFilePosition subBeginPos = file->getBeginPos();
        PsFilePosition subEndPos;

        if (!file->readRange(subBeginPos, subEndPos, proc, userdata))
        {
            return false;
        }
    }

    if (endIndex < (int)m_entryArray.size())
    {
        PsFilePtr file = m_entryArray[endIndex].file;

        PsFilePosition subBeginPos = file->getBeginPos();

        if (!file->readRange(subBeginPos, endPos, proc, userdata))
        {
            return false;
        }
    }

    return true;
}

bool CPsGroupFile::getMediaFormat(MFormat& fmt)
{
    if (m_entryArray.size() <= 0)
    {
        return false;
    }

    PsFilePtr file = m_entryArray[0].file;

    return file->getMediaFormat(fmt);
}

bool CPsGroupFile::openEx(const FILE_LIST& files)
{
    int index = 0;
    for (int i = 0; i < files.count; i ++)
    {
        std::shared_ptr<CPsFile> file(new CPsFile());
        file->setFileIndex(index);

        if (!file->open(files.filePath[i]))
        {
            continue;
        }

        FileEntry entry;
        entry.index = index;
        entry.file = file;
        entry.filepath = files.filePath[i];

		m_entryArray.push_back(entry);

        index ++;
    }

    onOpen();

    return index > 0;
}

bool CPsGroupFile::openEx(const StringArray& filepaths)
{
    int index = 0;
    for (size_t i = 0; i < filepaths.size(); i ++)
    {
        std::shared_ptr<CPsFile> file(new CPsFile());
        file->setFileIndex(index);

        if (!file->open(filepaths[i].c_str()))
        {
            continue;
        }

        FileEntry entry;
        entry.index = index;
        entry.file = file;
        entry.filepath = filepaths[i];

        index ++;
    }

    onOpen();

    return index > 0;
}


int CPsGroupFile::getFileCount()
{
    return (int)m_entryArray.size();
}

void CPsGroupFile::closeAllEntry()
{
    m_entryArray.clear();
}

const char* CPsGroupFile::getFilePath(int index)
{
    if (index < 0 || index >= (int)m_entryArray.size())
    {
        return "";
    }
    return m_entryArray[index].filepath.c_str();
}

size_t CPsGroupFile::findEntry(size_t offset, time_t t, PsFileSeekMode seekMode)
{
    size_t idx = -1;
    for (size_t i = offset; i < m_entryArray.size(); i ++)
    {
        PsFilePosition position = (seekMode == kSeekKeyFrame) ? m_entryArray[i].file->getBeginKeyPos() : m_entryArray[i].file->getBeginPos();
        if (position.time > t)
        {
            break;
        }
        else if (position.time == t)
        {
            idx = i;
            break;
        }
        else
        {
            idx = i;
        }
    }
    return idx;
}

void CPsGroupFile::onOpen()
{
	// pass
}
